package com.gitee.threefish.idea.json.components;

/*
 *
 * @author Nekio
 */

// <editor-fold defaultstate="collapsed" desc="Libraries">

import com.gitee.threefish.idea.json.util.JsonIcons;
import org.json.JSONArray;
import org.json.JSONObject;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.URI;

public class TreeChild extends JPanel {
    private final String SEPARATOR = "|";
    private JTree tree;

    private JPopupMenu popup;
    private JMenuItem popCopyKey;
    private JMenuItem popCopyValue;
    private JMenuItem popCopyNode;
    private JMenuItem popCopyNodePath;

    private JSONObject root;
    private String nodeName;

    public TreeChild(JSONObject root) {
        this.root = root;

        activate();
    }

    private void activate() {
        loadInfo();
        loadPopup();
        loadListeners();
    }

    private void loadInfo() {
        this.setLayout(new BorderLayout());

        DefaultMutableTreeNode treeNodes = addBranch(null, root);
        tree = new JTree(treeNodes);

        tree.setCellRenderer(new DefaultTreeCellRenderer() {


            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean isLeaf, int row, boolean focused) {
                this.closedIcon = JsonIcons.close;
                this.openIcon = JsonIcons.open;
                this.leafIcon = JsonIcons.leaf1;

                Component component = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);

                String trimValue = value.toString().replaceAll("\\s+", "");
                if (value.toString().contains(" [List]")) {
                    setIcon(JsonIcons.list);
                } else if (trimValue.toUpperCase().contains("=FALSE")) {
                    setIcon(JsonIcons.leaf0);
                } else if (trimValue.toUpperCase().contains("=NULL")) {
                    setIcon(JsonIcons.leaf0);
                } else if (trimValue.contains("=0")) {
                    setIcon(JsonIcons.leaf0);
                } else if (trimValue.endsWith("=")) {
                    setIcon(JsonIcons.warning);
                }

                return component;
            }
        });

        JScrollPane scroll = new JScrollPane();
        scroll.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        scroll.getViewport().add(tree);

        this.add(BorderLayout.CENTER, scroll);
    }

    private void loadPopup() {
        popup = new JPopupMenu();

        popCopyKey = new JMenuItem("复制键");
        popup.add(popCopyKey);

        popCopyValue = new JMenuItem("复制值");
        popup.add(popCopyValue);

        popCopyNode = new JMenuItem("复制节点");
        popup.add(popCopyNode);

        popCopyNodePath = new JMenuItem("复制节点路径");
        popup.add(popCopyNodePath);

        tree.add(popup);
    }

    private void loadListeners() {
        tree.addTreeSelectionListener(e -> {
            nodeName = e.getPath().toString().replace(", ", SEPARATOR);
        });

        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent mouse) {
                if (mouse.getClickCount() == 2) {
                    tryToOpen(getStringValueNode());
                }
            }
        });

        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent mouse) {
                if (mouse.getButton() == MouseEvent.BUTTON3) {
                    popup.show(tree, mouse.getX(), mouse.getY());
                }
            }
        });

        popCopyKey.addActionListener(evt -> toClipboard(getStringKeyNode()));

        popCopyValue.addActionListener(evt -> toClipboard(getStringValueNode()));

        popCopyNode.addActionListener(evt -> toClipboard(getStringNode()));

        popCopyNodePath.addActionListener(evt -> toClipboard(nodeName));
    }

    private DefaultMutableTreeNode addBranch(DefaultMutableTreeNode treeNode, JSONObject json) {
        DefaultMutableTreeNode currentNode = new DefaultMutableTreeNode();
        if (treeNode != null) {
            treeNode.add(currentNode);
        }

        String nodeName = null;
        String keyString = null;
        Object keyValue = null;

        for (Object key : json.keySet()) {
            keyString = (String) key;
            keyValue = json.get(keyString);

            if (keyValue instanceof JSONObject || keyValue instanceof JSONArray) {
                nodeName = keyString;
            } else {
                nodeName = keyString + " = " + keyValue.toString();
            }

            detectJsonType(currentNode, keyValue, nodeName);
        }

        return currentNode;
    }

    private void readJsonArrayKeyValues(DefaultMutableTreeNode treeNode, JSONArray jsonArray, String name) {
        boolean isJsonList = false;
        // Only used in case of key instanceof JSONObject
        DefaultMutableTreeNode currentNode = new DefaultMutableTreeNode(name + " [List]");
        String aux = null;
        for (Object key : jsonArray) {

            if (!(key instanceof JSONObject)) {
                isJsonList = true;
                currentNode.add(new DefaultMutableTreeNode(name + " = " + key.toString()));
                continue;
            } else {
                aux = name;
            }

            detectJsonType(treeNode, key, aux);
        }

        if (isJsonList) {
            treeNode.add(currentNode);
        }
    }

    private void detectJsonType(DefaultMutableTreeNode treeNode, Object object, String name) {
        if (object instanceof JSONObject) {
            addBranch(treeNode, (JSONObject) object);
        } else if (object instanceof JSONArray) {
            readJsonArrayKeyValues(treeNode, (JSONArray) object, name);
        } else {
            treeNode.add(new DefaultMutableTreeNode(name));
        }
    }

    public void expandTree() {
        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }
    }

    public void collapseTree() {
        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.collapseRow(i);
        }
    }

    private String getStringKeyNode() {
        String text = "";

        try {
            text = getStringNode();
            text = text.substring(0, text.lastIndexOf("=") - 1);
            text = text.trim();
        } catch (Exception e) {
        }

        return text;
    }

    private String getStringValueNode() {
        String text = "";

        try {
            text = getStringNode();
            text = text.substring(text.lastIndexOf("=") + 1);
            text = text.substring(0, text.length());
            text = text.trim();
        } catch (Exception e) {
        }

        return text;
    }

    private String getStringNode() {
        String text = "";

        try {
            text = nodeName;
            text = text.substring(text.lastIndexOf(SEPARATOR) + 1);
            text = text.substring(0, text.length() - 1);
        } catch (Exception e) {
        }

        return text;
    }

    private void toClipboard(String text) {
        StringSelection stringSelection = new StringSelection(text);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(stringSelection, null);
    }

    private void tryToOpen(String text) {
        if (Desktop.isDesktopSupported()) {

            try {
                Desktop.getDesktop().browse(new URI(text));
            } catch (Exception e) {
                try {
                    File file = new File(text);
                    if (file.exists()) {
                        Desktop.getDesktop().open(file);
                    }
                } catch (Exception ex) {
                }
            }
        }

    }
}
